﻿using DevExpress.Utils;
using DevExpress.XtraTreeList.Nodes;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using XCI.Core;
using XCI.Extensions;
using XCI.Helper;
using XCI.Sys.Filter;
using XCI.Sys.Model;
using XCI.Windows;

namespace XCI.Sys.Service
{
    /// <summary>
    /// 系统字典服务
    /// </summary>
    public class SysDicService
    {
        protected static Dictionary<string, Dic> DicListCache;
        protected static Dictionary<string, SMap> DicNameCache;
        public static SysDicService Instance { get; set; } = new SysDicService();
        protected const string RootUrl = "/api/sys/dic";

        public int GetDicNodeImageIndex(TreeListNode node)
        {
            var index = 0;
            if (node.HasChildren && node.Expanded) index = 1;
            else if (node.HasChildren) index = 2;
            return index;
        }

        public SvgImageCollection GetDicCategoryImageCollection()
        {
            var imageCollection1 = new DevExpress.Utils.SvgImageCollection();
            if (WinFormHelper.IsDesignMode()) return imageCollection1;
            imageCollection1.Insert(0, "actions_book", R.DicCategoryTreeSvgImage);
            imageCollection1.Insert(1, "folder_open", R.TreeOpenFolderSvgImage);
            imageCollection1.Insert(2, "folder_close", R.TreeCloseFolderSvgImage);
            return imageCollection1;
        }

        /// <summary>
        /// 新建字典类型对象
        /// </summary>
        public Task<SysDicCategory> NewDicCategoryAsync(string parentId)
        {
            return Task.FromResult(new SysDicCategory
            {
                ParentId = parentId
            });
        }

        /// <summary>
        /// 复制字典类型
        /// </summary>
        /// <param name="id">主键</param>
        public async Task CopyDicCategoryAsync(string id)
        {
            var model = await SelectDicCategoryByIdAsync(id);
            model.Id = null;
            model.Spell = null;
            model.Name += " - 复制";
            await SaveDicCategoryAsync(true, model);
        }

        /// <summary>
        /// 保存字典类型
        /// </summary>
        /// <param name="created">是否新增</param>
        /// <param name="model">字典对象</param>
        /// <returns>成功返回true</returns>
        public async Task<BoolResult> SaveDicCategoryAsync(bool created, SysDicCategory model)
        {
            return await App.Client.PostAsBoolResultAsync($"{RootUrl}/{(created ? "insertCategory" : "updateCategory")}", model);
        }

        /// <summary>
        /// 删除字典类型
        /// </summary>
        /// <param name="ids">主键字符串</param>
        /// <returns>成功返回true</returns>
        public async Task DeleteDicCategoryAsync(string ids)
        {
            await App.Client.PostAsync($"{RootUrl}/deleteCategory", new { ids });
        }

        /// <summary>
        /// 根据主键获取字典类型对象
        /// </summary>
        /// <param name="id">字典类型主键</param>
        public async Task<SysDicCategory> SelectDicCategoryByIdAsync(string id)
        {
            return await App.Client.PostAsync<SysDicCategory>($"{RootUrl}/selectCategoryById", new { id });
        }

        /// <summary>
        /// 根据字典类型编码获取字典类型对象
        /// </summary>
        /// <param name="code">字典类型编码</param>
        /// <returns>成功返回模型对象</returns>
        public async Task<SysDicCategory> SelectDicCategoryByCodeAsync(string code)
        {
            return await App.Client.PostAsync<SysDicCategory>($"{RootUrl}/selectCategoryByCode", new { code });
        }

        /// <summary>
        /// 根据主键获取字典类型对象
        /// </summary>
        /// <param name="args">编辑参数</param>
        public Task<SysDicCategory> GetOrCreateDicCategoryAsync(EditFormArgs args)
        {
            if (args == null || args.Created) return NewDicCategoryAsync(args?.ParentId);
            return SelectDicCategoryByIdAsync(args.Id);
        }

        /// <summary>
        /// 保存节点拖拽数据
        /// </summary>
        /// <param name="keyValues">修改的数据集合</param>
        /// <returns>成功返回true</returns>
        public async Task UpdateDicCategoryDndAsync(List<PrimaryKeyValue> keyValues)
        {
            await App.Client.PostAsync($"{RootUrl}/updateCategoryNodeDrag", WinFormHelper.ToTreeNodeDnds(keyValues));
        }

        /// <summary>
        /// 查询字典类型列表
        /// </summary>
        /// <param name="filter">过滤条件</param>
        public async Task<List<SysDicCategory>> SelectDicCategoryListAsync(SysDicCategoryFilter filter)
        {
            return await App.Client.PostAsync<List<SysDicCategory>>($"{RootUrl}/selectCategoryList", filter);
        }

        public SvgImageCollection GetDicImageCollection()
        {
            return DicTreeListLookUpEdit.GetDicImageCollection();
        }

        /// <summary>
        /// 新建字典对象
        /// </summary>
        public Task<SysDic> NewDicAsync(string parentId, string code)
        {
            return Task.FromResult(new SysDic
            {
                ParentId = parentId,
                Code = code,
                Status = true
            });
        }

        /// <summary>
        /// 复制字典对象
        /// </summary>
        /// <param name="id">主键</param>
        public async Task CopyDicAsync(string id)
        {
            var model = await SelectDicByIdAsync(id);
            model.Id = null;
            model.Spell = null;
            model.Name += " - 复制";
            await SaveDicAsync(true, model);
        }

        /// <summary>
        /// 保存字典
        /// </summary>
        /// <param name="created">是否新增</param>
        /// <param name="model">字典对象</param>
        /// <returns>成功返回true</returns>
        public async Task<BoolResult> SaveDicAsync(bool created, SysDic model)
        {
            var result = await App.Client.PostAsBoolResultAsync($"{RootUrl}/{(created ? "insertDic" : "updateDic")}", model);
            RefreshLocalCache();
            return result;
        }

        /// <summary>
        /// 批量保存数据字典
        /// </summary>
        /// <param name="m">模型对象</param>
        /// <param name="content">批量内容数组</param>
        public async Task<BoolResult> BatchInsertDicAsync(SysDic m, string[] content)
        {
            var resultList = new List<BoolResult>();
            foreach (var item in content)
            {
                if (string.IsNullOrWhiteSpace(item)) continue;
                var itemArray = item.Split(new[] { ':' }, StringSplitOptions.RemoveEmptyEntries);
                if (itemArray.Length == 0) continue;
                string name = itemArray[0];
                string value = name;
                if (itemArray.Length > 1)
                {
                    value = itemArray[1];
                }

                var model = new SysDic
                {
                    ParentId = m.ParentId,
                    Code = m.Code,
                    Name = name,
                    Value = value,
                    Status = true
                };
                resultList.Add(await SaveDicAsync(true, model));
            }

            if (resultList.Any(p => p.Fail))
            {
                StringBuilder msg = new StringBuilder();
                for (var index = 0; index < resultList.Count; index++)
                {
                    var item = resultList[index];
                    if (item.Success) continue;
                    msg.AppendLine(item.Msg);
                    if (index > 10)
                    {
                        break;
                    }
                }
                return new BoolResult(false, msg.ToString());
            }
            RefreshLocalCache();
            return BoolResult.True;
        }

        /// <summary>
        /// 删除字典
        /// </summary>
        /// <param name="ids">主键字符串</param>
        /// <returns>成功返回true</returns>
        public async Task DeleteDicAsync(string ids)
        {
            await App.Client.PostAsync($"{RootUrl}/deleteDic", new { ids });
            RefreshLocalCache();
        }

        /// <summary>
        /// 修改字典状态
        /// </summary>
        /// <param name="ids">主键字符串</param>
        /// <param name="status">状态 [true-启用, false-禁用]</param>
        /// <returns>成功返回true</returns>
        public async Task UpdateDicStatusAsync(string ids, bool status)
        {
            await App.Client.PostAsync($"{RootUrl}/updateDicStatus", new { ids, status });
        }

        /// <summary>
        /// 根据主键获取字典对象
        /// </summary>
        /// <param name="id">字典主键</param>
        public async Task<SysDic> SelectDicByIdAsync(string id)
        {
            return await App.Client.PostAsync<SysDic>($"{RootUrl}/selectDicById", new { id });
        }

        /// <summary>
        /// 根据主键获取字典对象
        /// </summary>
        /// <param name="args">编辑参数</param>
        public async Task<SysDic> GetOrCreateDicAsync(EditFormArgs args)
        {
            if (args == null || args.Created) return await NewDicAsync(args?.ParentId, args?.Code);
            return await SelectDicByIdAsync(args.Id);
        }

        /// <summary>
        /// 保存节点拖拽数据
        /// </summary>
        /// <param name="keyValues">修改的数据集合</param>
        /// <returns>成功返回true</returns>
        public async Task UpdateDicDndAsync(List<PrimaryKeyValue> keyValues)
        {
            await App.Client.PostAsync($"{RootUrl}/updateDicNodeDrag", WinFormHelper.ToTreeNodeDnds(keyValues));
        }

        /// <summary>
        /// 查询字典列表
        /// </summary>
        /// <param name="filter">过滤条件</param>
        public async Task<List<SysDic>> SelectDicListAsync(SysDicFilter filter)
        {
            return await App.Client.PostAsync<List<SysDic>>($"{RootUrl}/selectDicList", filter);
        }

        /// <summary>
        /// 导出字典列表
        /// </summary>
        /// <param name="filePath">保存路径</param>
        /// <param name="filter">过滤条件</param>
        public async Task ExportAsync(string filePath, SysDicFilter filter)
        {
            await App.Client.DownloadAsync($"{RootUrl}/exportDic", filePath, filter);
        }

        /// <summary>
        /// 刷新服务端字典缓存
        /// </summary>
        public async Task RefreshServiceCacheAsync()
        {
            await App.Client.PostAsync($"{RootUrl}/refreshCache");
        }

        /// <summary>
        /// 刷新字典缓存
        /// </summary>
        public void RefreshLocalCache()
        {
            if (DicListCache == null) DicListCache = new Dictionary<string, Dic>();
            if (DicNameCache == null) DicNameCache = new Dictionary<string, SMap>();

            var list = AsyncHelper.RunSync(() => SelectDicListAsync(new SysDicFilter { Status = true }));
            DicListCache.Clear();
            DicNameCache.Clear();
            foreach (var item in list)
            {
                if (item.Code.IsEmpty()) continue;
                var dicItem = new DicItem();
                dicItem.Id = item.Id;
                dicItem.ParentId = item.ParentId;
                dicItem.Code = item.Code;
                dicItem.Name = item.Name;
                dicItem.Spell = item.Spell;
                dicItem.Value = item.Value;
                dicItem.Path = item.Path;

                if (DicListCache.TryGetValue(item.Code, out Dic val))
                {
                    val.Items.Add(dicItem);
                }
                else
                {
                    DicListCache.Add(item.Code, new Dic(item.Code, new List<DicItem> { dicItem }));
                }

                if (item.Value.IsEmpty()) continue;
                if (DicNameCache.TryGetValue(item.Code, out SMap smap))
                {
                    smap[item.Value] = item.Name;
                }
                else
                {
                    DicNameCache.Add(item.Code, SMap.New.Set(item.Value, item.Name));
                }
            }
        }

        /// <summary>
        /// 在缓存中查询字典列表
        /// </summary>
        /// <param name="code">字典类型编码</param>
        public Dic GetDicListFromCache(string code)
        {
            if (DicListCache == null)
            {
                DicListCache = new Dictionary<string, Dic>();
                RefreshLocalCache();
            }
            if (DicListCache.TryGetValue(code, out Dic val))
            {
                return val;
            }
            return new Dic(code, new List<DicItem>());
        }

        /// <summary>
        /// 在缓存中查询字典值对应的名称
        /// </summary>
        /// <param name="code">字典类型编码</param>
        /// <param name="value">字典值</param>
        /// <param name="defaultName">找不到指定的项值时返回的默认名称</param>
        public string GetDicNameByValueFromCache(string code, string value, string defaultName = R.Empty)
        {
            if (DicNameCache == null)
            {
                DicNameCache = new Dictionary<string, SMap>();
                RefreshLocalCache();
            }
            if (code.IsEmpty()) throw new ArgumentNullException(nameof(code), "字典类型编码");
            if (value.IsEmpty()) return defaultName;

            var result = string.Empty;
            if (DicNameCache.TryGetValue(code, out SMap smap) && smap.TryGetValue(value, out string name) && name.IsNotEmpty())
            {
                result = name;
            }

            return result.IsEmpty() ? defaultName : result;
        }
    }
}